package cn.kivensoft.util;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;

/** 动态扩展的缓存类, 以1024byte为单位动态扩展
 * @author kiven lee
 * @version 1.0
 * @since 2017-04-02
 */
final public class FastBuffer {
	private static final int B1 = 10; // Low array maximum capacity in bits.
	private static final int C1 = 1 << B1; // Low array maximum capacity (1024).
	private static final int M1 = C1 - 1; // Mask(1023)

	// Resizes up to 1024 maximum (32, 64, 128, 256, 512, 1024).
	private final byte[] _low = new byte[C1];
	// For larger capacity use multi-dimensional array.
	private byte[][] _high = new byte[1][];

	// Holds the current length.
	private int _length;

	// Holds current capacity.
	private int _capacity = C1;

	private char cacheChar;

	private void increaseCapacity() {
		int highIndex = _capacity >> B1;
		if (highIndex >= _high.length) { // Resizes _high.
			byte[][] tmp = new byte[_high.length << 1][];
			System.arraycopy(_high, 0, tmp, 0, _high.length);
			_high = tmp;
		}
		_high[highIndex] = new byte[C1];
		_capacity += C1;
	}

	private void increaseCapacity(int capacity) {
		while (capacity > _capacity) increaseCapacity();
	}

	public FastBuffer() {
		_high[0] = _low;
	}

	/** 初始化对象
	 * @param capacity 参考容量大小, 实际分配容量小于1024为二的幂指数, 大于1024为1024对齐
	 */
	public FastBuffer(int capacity) {
		int cap = _capacity;
		while (cap < capacity) cap += C1;
		_capacity = cap;
		if (cap > C1) {
			int high_len = cap >> B1;
			_high = new byte[high_len][];
			for (int i = 1; i < high_len; ++i)
				_high[i] = new byte[C1];
		}
		_high[0] = _low;
	}

	/** 缓冲区实际长度
	 * @return 长度
	 */
	public int length() {
		return _length;
	}

	/** 缓冲区容量大小
	 * @return 容量
	 */
	public int capacity() {
		return _capacity;
	}

	/** 缓冲区是否为空
	 * @return 是否为空
	 */
	public boolean isEmpty() {
		return _length == 0;
	}

	/** 设置缓冲区长度
	 * @param newLen 新的长度, 大于当前容量时分配新空间, 小于当前容量时直接设置
	 * @return this
	 */
	public FastBuffer setLength(int newLen) {
		if (newLen > _capacity) increaseCapacity(newLen);
		_length = newLen;
		return this;
	}

	public interface OnForEach {
		/** 缓冲区分片循环回调接口
		 * @param array 分片数组
		 * @param offset 起始偏移值
		 * @param length 有效长度
		 * @param result 上次调用后的结果
		 * @return 本次调用结果, 该返回值会在下一次回调时作为result参数
		 */
		int call(byte[] array, int offset, int length, int result);
	}

	/** 分片循环所有内部字节数组
	 * @param act 回调函数
	 */
	public void forEach(OnForEach act) {
		forEach(0, _length, 0, act);
	}

	/** 分片循环内部字节数组
	 * @param begin 起始位置
	 * @param end 结束位置
	 * @param init 回调OnforEach时的的初始值
	 * @param act 回调函数
	 */
	public void forEach(int begin, int end, int init, OnForEach act) {
		while (begin < end) {
			byte[] sub = _high[begin >> B1];
			int off = begin & M1;
			int x = C1 - off, y = end - begin;
			int len = Math.min(x, y);
			init = act.call(sub, off, len, init);
			if (init == -1) return;
			begin += len;
		}
	}

	/** 生成一个包含所有内部数据的byte[]拷贝
	 * @return utf8转码后的字节数组
	 */
	public byte[] getBytes() {
		return getBytes(0, _length);
	}

	public BufChunk nextChunk() {
		byte[] chunk = _high[_length >> B1];
		int offset = _length & M1;
		int length = _low.length - offset;
		return new BufChunk(chunk, offset, length);
	}

	/** 生成一个包含指定起止位置的内部数据的byte[]拷贝
	 * @param begin 起始位置
	 * @param end 结束位置
	 * @return utf8转码后的字节数组
	 */
	public byte[] getBytes(int begin, int end) {
		int len = end - begin;
		byte[] ret = new byte[len];
		getBytes(begin, ret, 0, len);
		return ret;
	}

	/** 将包含指定起止位置的内部数据复制到目标数组byte[]中
	 * @param srcPos 起始位置
	 * @param dst 目标数组
	 * @param dstPos 目标数组起始位置
	 * @param length 拷贝长度
	 */
	public void getBytes(int srcPos, byte[] dst, int dstPos, int length) {
		forEach(srcPos, srcPos + length, dstPos, (va, off, len, ret) -> {
			System.arraycopy(va, off, dst, ret, len);
			return ret + len;
		});
	}

	/** 设置长度为0, 不清理内容
	 * @return this
	 */
	public FastBuffer clear() {
		_length = 0;
		return this;
	}

	/** 填充value到指定范围
	 * @param value 填充值
	 * @param pos 起始位置
	 * @param length 填充长度
	 * @return this
	 */
	public FastBuffer fill(byte value, int pos, int length) {
		int newLen = pos + length;
		if (newLen >= _capacity) increaseCapacity(newLen);
		forEach(pos, newLen, 0, (va, off, len, ret) -> {
			for (int i = off, imax = off + len; i < imax; ++i)
				va[i] = value;
			return 0;
		});
		if (newLen > _length) _length = newLen;
		return this;
	}

	/** 获取指定位置的字节值
	 * @param index 指定位置
	 * @return byte
	 */
	public byte get(int index) {
		return index < C1 ? _low[index] : _high[index >> B1][index & M1];
	}

	/** 读取一个int
	 * @param index 指定位置, 向后读取4字节
	 * @return int
	 */
	public int getInt(int index) {
		return index + 4 > _length ? 0
				: ((get(index++) & 0xFF) << 24)
				| ((get(index++) & 0xFF) << 16)
				| ((get(index++) & 0xFF) << 8)
				| (get(index) & 0xFF);
	}

	/** 读取一个long
	 * @param index 指定位置, 向后读取8字节
	 * @return long
	 */
	public long getLong(int index) {
		return index + 8 > _length ? 0L
				: ((get(index++) & 0xFFL) << 56)
				| ((get(index++) & 0xFFL) << 48)
				| ((get(index++) & 0xFFL) << 40)
				| ((get(index++) & 0xFFL) << 32)
				| ((get(index++) & 0xFFL) << 24)
				| ((get(index++) & 0xFFL) << 16)
				| ((get(index++) & 0xFFL) << 8)
				| (get(index) & 0xFFL);
	}

	/** 读取一个float
	 * @param index 指定位置, 向后读取4字节
	 * @return float
	 */
	public float getFloat(int index) {
		int n = getInt(index);
		return n == 0 ? 0F : Float.intBitsToFloat(n);
	}

	/** 读取一个double
	 * @param index 指定位置, 向后读取8字节
	 * @return double
	 */
	public double getDouble(int index) {
		long n = getLong(index);
		return n == 0 ? 0D : Double.longBitsToDouble(n);
	}

	/** 设置指定位置的字节内容
	 * @param index 指定位置
	 * @param src 字节内容
	 * @return this
	 */
	public FastBuffer set(int index, byte src) {
		if (index < C1) _low[index] = src;
		else _high[index >> B1][index & M1] = src;
		return this;
	}

	/** 复制源数组的内容到指定位置
	 * @param index 指定位置 
	 * @param src 源数组
	 * @return this
	 */
	public FastBuffer set(int index, byte[] src) {
		return src == null ? this : set(index, src, 0, src.length);
	}

	/** 复制源数组的内容到指定位置
	 * @param index 指定位置
	 * @param src 源数组
	 * @param offset 源数组起始偏移
	 * @param count 复制数量
	 * @return this
	 */
	public FastBuffer set(int index, byte[] src, int offset, int count) {
		if (src == null || src.length == 0) return this;

		int newLen = index + count;
		if (newLen > _capacity) increaseCapacity(newLen);
		forEach(index, newLen, offset, (va, off, len, ret) -> {
			System.arraycopy(src, ret, va, off, len);
			return ret + len;
		});

		if (newLen > _length) _length = newLen;
		return this;
	}

	/** 返回指定value在数组中的索引
	 * @param value 要查找的值
	 * @return -1表示未找到, 否则返回元素所在索引位
	 */
	public int indexOf(byte value) {
		return indexOf(value, 0, _length);
	}

	/** 返回指定value在区间中的索引
	 * @param value 要查找的值
	 * @param begin 查找区间起始位置
	 * @param end 查找区间结束位置
	 * @return -1表示未找到, 否则返回元素所在索引位
	 */
	public int indexOf(byte value, int begin, int end) {
		IntNumber result = new IntNumber(-1);
		forEach(begin, end, 0, (va, off, len, ret) -> {
			for (int i = off, imax = off + len; i < imax; ++i) {
				if (va[i] == value) {
					result.setValue(ret + i);
					return -1;
				}
			}
			return 0;
		});
		return result.getValue();
	}

	/** 返回指定value在区间中的索引
	 * @param value 要比对的数组
	 * @param begin 查找区间起始位置
	 * @param end 查找区间结束位置
	 * @return -1表示未找到, 否则返回元素所在索引位
	 */
	public int indexOf(byte[] value, int begin, int end) {
		if (value == null || value.length == 0) return -1;
		int vlen = value.length;
		byte first = value[0];
		IntNumber result = new IntNumber(-1);
		forEach(begin, end, 0, (va, off, len, ret) -> {
			for (int i = off, imax = off + len - vlen + 1; i < imax; ++i) {
				if (va[i] == first) {
					int match_len = 1;
					for (; match_len < vlen; ++match_len) {
						if (va[i + match_len] != value[match_len]) break;
					}
					if (match_len >= vlen) {
						result.setValue(ret + i);
						return -1;
					}
				}
			}
			return 0;
		});
		return result.getValue();
	}

	/** 判断数组是否以value开头
	 * @param value 要比对的数组
	 * @return true: 匹配, false: 不匹配
	 */
	public boolean startsWith(byte[] value) {
		return indexOf(value, 0, _length) != -1;
	}

	/** 追加一个字节
	 * @param value 值
	 * @return this
	 */
 	public FastBuffer append(byte value) {
		if (_length >= _capacity) increaseCapacity();
		_high[_length >> B1][_length & M1] = value;
		++_length;
		return this;
	}

	/** 添加字节数组内容到缓冲区
	 * @param value 字节数组
	 * @return this
	 */
	public FastBuffer append(byte[] value) {
		return value == null ? this : append(value, 0, value.length);
	}

	/** 添加指定源起始位置和长度的内容
	 * @param value 源数组
	 * @param offset 起始位置
	 * @param length 读取数量
	 * @return this
	 */
	public FastBuffer append(byte[] value, int offset, int length) {
		return set(_length, value, offset, length);
	}

	/** 以utf8格式添加字符 */
	private void appendChar(char value) {
		if (value < 0x80) {
			append((byte) value);
		} else if (value < 0x800) {
			append((byte) ((value >> 6) | 0xC0));
			append((byte) ((value & 0x3F) | 0x80));
		} else if (value < 0xD800) {
			append((byte) ((value >> 12) | 0xE0));
			append((byte) (((value >> 6) & 0x3F) | 0x80));
			append((byte) ((value & 0x3F) | 0x80));
		} else if (value < 0xDC00) {
			// 0xD800~0xDBFF之间表示为高位代码点
			cacheChar = value;
		} else {
			// 0xDC00~0xDFFF为低位代码点
			int c = ((cacheChar & 0x3FF) << 10) | (value & 0x3FF);
			append((byte) ((c >> 18) | 0xF0));
			append((byte) (((c >> 12) & 0x3F) | 0x80));
			append((byte) (((c >> 6) & 0x3F) | 0x80));
			append((byte) ((c & 0x3F) | 0x80));
		}
	}

	/** 以utf8方式添加字符
	 * @param value 字符
	 * @return this
	 */
	public FastBuffer append(char value) {
		appendChar(value);
		return this;
	}

	/** 以utf8方式添加字符串内容
	 * @param chars 源
	 * @param off 偏移
	 * @param len 长度
	 * @return this
	 */
	public FastBuffer append(char[] chars, int off, int len) {
		if (chars == null || chars.length == 0) return this;
		for (int i = off, imax = off + len; i < imax; ++i)
			appendChar(chars[i]);
		return this;
	}

	/** 以utf8方式添加字符串内容
	 * @param text 源
	 * @return this
	 */
	public FastBuffer append(String text) {
		return text == null ? this : append(text, 0, text.length());
	}

	/** 以utf8方式添加字符串内容
	 * @param text 源
	 * @param off 偏移
	 * @param len 长度
	 * @return this
	 */
	public FastBuffer append(String text, int off, int len) {
		if (text == null || text.isEmpty()) return this;
		for (int i = off, imax = off + len; i < imax; ++i)
			appendChar(text.charAt(i));
		return this;
	}

	/** 添加一个int */
	public FastBuffer append(short value) {
		int len = _length;
		if (len + 2 > _capacity) increaseCapacity();
		_high[len >> B1][len++ & M1] = (byte) ((value >> 8) & 0xff);
		_high[len >> B1][len & M1] = (byte) (value & 0xff);
		_length += 2;
		return this;
	}

	/** 添加一个int */
	public FastBuffer append(int value) {
		int len = _length;
		if (len + 4 > _capacity) increaseCapacity();
		_high[len >> B1][len++ & M1] = (byte) ((value >> 24) & 0xff);
		_high[len >> B1][len++ & M1] = (byte) ((value >> 16) & 0xff);
		_high[len >> B1][len++ & M1] = (byte) ((value >> 8) & 0xff);
		_high[len >> B1][len & M1] = (byte) (value & 0xff);
		_length += 4;
		return this;
	}

	/** 添加一个long */
	public FastBuffer append(long value) {
		int len = _length;
		if (len + 4 > _capacity) increaseCapacity();
		_high[len >> B1][len++ & M1] = (byte) ((value >> 56) & 0xff);
		_high[len >> B1][len++ & M1] = (byte) ((value >> 48) & 0xff);
		_high[len >> B1][len++ & M1] = (byte) ((value >> 40) & 0xff);
		_high[len >> B1][len++ & M1] = (byte) ((value >> 32) & 0xff);
		_high[len >> B1][len++ & M1] = (byte) ((value >> 24) & 0xff);
		_high[len >> B1][len++ & M1] = (byte) ((value >> 16) & 0xff);
		_high[len >> B1][len++ & M1] = (byte) ((value >> 8) & 0xff);
		_high[len >> B1][len & M1] = (byte) (value & 0xff);
		_length += 8;

		return this;
	}

	/** 添加一个float */
	public FastBuffer append(float value) {
		return append(Float.floatToRawIntBits(value));
	}

	/** 添加一个double */
	public FastBuffer append(double value) {
		return append(Double.doubleToLongBits(value));
	}

	/** 在指定位置插入数组(指定位置之后的元素会往后移动, 速度较慢, 不建议使用)
	 * @param index 索引位
	 * @param value 插入内容
	 * @return this
	 */
	public FastBuffer insert(int index, byte[] value) {
		return value == null ? this : insert(index, value, 0, value.length);
	}

	/** 在指定位置插入数组(指定位置之后的元素会往后移动, 速度较慢, 不建议使用)
	 * @param index 索引位
	 * @param value 插入内容
	 * @param offset value起始位置
	 * @param length 插入数量
	 * @return this
	 */
	public FastBuffer insert(int index, byte[] value, int offset, int length) {
		if (value == null || value.length == 0) return this;
		int newLen = _length + length;
		if (newLen > _capacity) increaseCapacity(newLen);
		for (int i = _length - 1, j = newLen - 1; i >= index; --i, --j)
			_high[j >> B1][j & M1] = _high[i >> B1][i & M1];
		for (int i = index, imax = index + length, j = offset; i < imax; ++i, ++j)
			_high[i >> B1][i & M1] = value[j];
		_length = newLen;
		return this;
	}

	/** 删除指定位置的元素(后面的值会前移)
	 * @param index 索引位
	 * @return this
	 */
	public FastBuffer delete(int index) {
		return delete(index, index + 1);
	}

	/** 删除指定区间的元素(后面的值会前移)
	 * @param begin 起始位置
	 * @param end 结束位置
	 * @return this
	 */
	public FastBuffer delete(int begin, int end) {
		for (int i = end, j = begin; i < _length; ++i, ++j)
			_high[j >> B1][j & M1] = _high[i >> B1][i & M1];
		_length -= end - begin;
		return this;
	}

	/** 返回一个OutputStream类型的对象提供写入使用，在OutputStream工作期间，不要使用Fmt的其它方法
	 * @return 输出流
	 */
	public OutputStream asOutputStream() {
		return new OutputStream() {
			@Override
			public void write(int b) {
				append((byte) b);
			}

			@Override
			public void write(byte[] b, int off, int len) {
				append(b, off, len);
			}
		};
	}

	/** 返回一个Writer输出流，在输出流使用期间，不要使用Fmt的其它方法
	 * @return 输出流
	 */
	public Writer asWriter() {
		return new Writer() {
			@Override
			public void write(int c) {
				FastBuffer.this.appendChar((char) c);
			}

			@Override
			public void write(char[] cbuf, int off, int len) {
				FastBuffer.this.append(cbuf, off, len);
			}

			@Override public void flush() { }

			@Override public void close() { }

		};
	}

	/** 返回一个InpuutStream输入流，在输入流使用期间，不要使用Fmt的其它方法
	 * @return 输入流
	 */
	public InputStream asInputStream() {
		return new InputStream() {
			int index = 0;

			@Override
			public int read() {
				return index < _length ? ((int) get(index++)) & 0xFF : -1;
			}
		};
	}

	/** 返回一个Reader输入流，在输入流使用期间，不要使用Fmt的其它方法
	 * @return 输入流
	 */
	public Reader asReader() {
		return new Reader() {
			int index = 0;

			@Override
			public int read(char[] cbuf, int off, int len) {
				int p = off, pmax = off + len, i = index, imax = _length;
				while (p < pmax && i < imax) {
					int b = get(i++) & 0xFF;
					if (b >= 0x80) {
						int next = b < 0xE0 ? 1 : b < 0xF0 ? 2 : b < 0xF8 ? 3 : b < 0xFC ? 4 : 5;
						b &= 0x3F >> next;
						int bmax = i + next;
						if (bmax <= imax)
							while (i < bmax)
								b = (b << 6) | (get(i++) & 0x3F);
					}
					cbuf[p++] = (char) b;
				}
				index = i;
				return p - off;
			}

			@Override
			public void close() { }
		};
	}
	
}
